// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using CommunityServer.Components;
using System.Text;
using System.IO;

namespace CommunityServer.Controls 
{

	/// <summary>
	/// Summary description for Pager.
	/// </summary>
	public class Pager : Label, IPagedControl, INamingContainer 
	{

		#region Member variables and constructor
		protected CSContext csContext = CSContext.Current;
		HyperLink previousLink;
		HyperLink nextLink;
		HyperLink firstLink;
		HyperLink lastLink;
		HyperLink[] pagingHyperLinks;

		// ***************************************************
		// Controls
		//
		/// <summary>
		/// Override how this control handles its controls collection
		/// </summary>
		/// 
		public override ControlCollection Controls 
		{

			get 
			{
				EnsureChildControls();
				return base.Controls;
			}

		}

		// *********************************************************************
		//  CreateChildControls
		//
		/// <summary>
		/// This event handler adds the children controls and is resonsible
		/// for determining the template type used for the control.
		/// </summary>
		/// 
		// ********************************************************************/ 
		protected override void CreateChildControls() 
		{
			Controls.Clear();

			// Add Page buttons
			//
			AddPageLinks();

			// Add Previous Next child controls
			//
			AddPreviousNextLinks();

			// Add First Last child controls
			//
			AddFirstLastLinks();

		}
		#endregion

		#region Render functions
		protected override void Render(HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			// Do we have data?
			//
			if (totalPages <= 1)
				return;

			// Render the paging buttons
			//
			writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);

			// Render the first button
			//
			RenderFirst(writer);

			// Render the previous button
			//
			RenderPrevious(writer);
            
			// Render the page button(s)
			//
			RenderPagingButtons(writer);

			// Render the next button
			//
			RenderNext(writer);

			// Render the last button
			//
			RenderLast(writer);

			//writer.RenderEndTag();

		}

		void RenderFirst (HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			if ((PageIndex >= 3) && (totalPages > 5)) 
			{
				firstLink.RenderControl(writer);

				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);
			}
		}

		void RenderLast (HtmlTextWriter writer) 
		{
			int totalPages = CalculateTotalPages();

			if (((PageIndex + 3) < totalPages) && (totalPages > 5)) 
			{
				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);

				lastLink.RenderControl(writer);
			}

		}

		void RenderPrevious (HtmlTextWriter writer) 
		{
			Literal l;

			if (HasPrevious) 
			{
				previousLink.RenderControl(writer);

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);
			}

		}

		void RenderNext(HtmlTextWriter writer) 
		{
			Literal l;

			if (HasNext) 
			{

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);

				nextLink.RenderControl(writer);
			}

		}

		void RenderButtonRange(int start, int end, HtmlTextWriter writer) 
		{

			for (int i = start; i < end; i++) 
			{

				// Are we working with the selected index?
				//
				if (PageIndex == i) 
				{

					// Render different output
					//
					Literal l = new Literal();
					//l.Text = "<span class=\"currentPage\">[" + (i + 1).ToString() + "]</span>";
					l.Text = (i + 1).ToString();

					l.RenderControl(writer);
				} 
				else 
				{
					pagingHyperLinks[i].RenderControl(writer);
				}
				if ( i < (end - 1) )
					writer.Write(" ");

			}

		}

		void RenderPagingButtons(HtmlTextWriter writer) 
		{
			int totalPages;

			// Get the total pages available
			//
			totalPages = CalculateTotalPages();

			// If we have <= 5 pages display all the pages and exit
			//
			if ( totalPages <= 5) 
			{
				RenderButtonRange(0, totalPages, writer);
			} 
			else 
			{

				int lowerBound = (PageIndex - 2);
				int upperBound = (PageIndex + 3);

				if (lowerBound <= 0) 
					lowerBound = 0;

				if (PageIndex == 0)
					RenderButtonRange(0, 5, writer);

				else if (PageIndex == 1)
					RenderButtonRange(0, (PageIndex + 4), writer);

				else if (PageIndex < (totalPages - 2))
					RenderButtonRange(lowerBound, (PageIndex + 3), writer);

				else if (PageIndex == (totalPages - 2))
					RenderButtonRange((totalPages - 5), (PageIndex + 2), writer);

				else if (PageIndex == (totalPages - 1))
					RenderButtonRange((totalPages - 5), (PageIndex + 1), writer);
			}
		}
		#endregion

		#region ControlTree functions
		void AddPageLinks() 
		{
			// First add the lower page buttons
			//
			pagingHyperLinks = new HyperLink[CalculateTotalPages()];

			// Create the buttons and add them to 
			// the Controls collection
			//
			for (int i = 0; i < pagingHyperLinks.Length; i++) 
			{
				pagingHyperLinks[i] = new HyperLink();
				pagingHyperLinks[i].EnableViewState = false;
				pagingHyperLinks[i].Text = (i + 1).ToString();
				pagingHyperLinks[i].ID = (i + 1).ToString();
				pagingHyperLinks[i].NavigateUrl = CreatePagerURL((i + 1).ToString());
				Controls.Add(pagingHyperLinks[i]);
			}
		}

		void AddFirstLastLinks() 
		{
			int start = 1;
			firstLink = new HyperLink();
			firstLink.ID = "First";
			firstLink.Text = ResourceManager.GetString("Utility_Pager_firstButton");
			firstLink.NavigateUrl = CreatePagerURL(start.ToString());
			Controls.Add(firstLink);

			int last = CalculateTotalPages();
			lastLink = new HyperLink();
			lastLink.ID = "Last";
			lastLink.Text = ResourceManager.GetString("Utility_Pager_lastButton");
			lastLink.NavigateUrl = CreatePagerURL(last.ToString());
			Controls.Add(lastLink);
		}

		void AddPreviousNextLinks() 
		{
			int previous;
			
			if (this.PageIndex < 2)
				previous = 1;
			else
				previous = this.PageIndex;

			previousLink = new HyperLink();
			previousLink.ID = "Prev";
			previousLink.Text = ResourceManager.GetString("Utility_Pager_previousButton");
			previousLink.NavigateUrl = CreatePagerURL(previous.ToString());
			Controls.Add(previousLink);

			int next = this.PageIndex + 2;
			nextLink = new HyperLink();
			nextLink.ID = "Next";
			nextLink.Text = ResourceManager.GetString("Utility_Pager_nextButton");
			nextLink.NavigateUrl = CreatePagerURL(next.ToString());
			Controls.Add(nextLink);
		}
		#endregion

		#region Private Properties
		private bool HasPrevious 
		{
			get 
			{
				if (PageIndex > 0)
					return true;

				return false;
			}
		}

		private bool HasNext 
		{
			get 
			{
				if (PageIndex + 1 < CalculateTotalPages() )
					return true;

				return false;
			}
		}
		#endregion

		#region Helper methods and Public Properties
		protected virtual string CreatePagerURL(string pageIndex)
		{
			if(!Globals.IsNullorEmpty(UrlPattern))
				return string.Format(UrlPattern,pageIndex);

			if (csContext.CurrentUri.AbsoluteUri.IndexOf("?") == -1)
			{
				return csContext.CurrentUri.AbsoluteUri.ToString() + "?PageIndex=" + pageIndex;
			}
			else
			{
				if (csContext.CurrentUri.AbsoluteUri.IndexOf("PageIndex=") == -1)
					return csContext.CurrentUri.AbsoluteUri.ToString() + "&PageIndex=" + pageIndex;
				else
				{
					return Regex.Replace(csContext.CurrentUri.AbsoluteUri.ToString(), @"PageIndex=(\d+\.?\d*|\.\d+)", "PageIndex=" + pageIndex);
				}
			}
		}

		string _urlPattern = null;
		public string UrlPattern
		{
			get { return _urlPattern;}
			set {_urlPattern = value;}
		}


		// *********************************************************************
		//  CalculateTotalPages
		//
		/// <summary>
		/// Static that caculates the total pages available.
		/// </summary>
		/// 
		// ********************************************************************/
		public virtual int CalculateTotalPages() 
		{
			int totalPagesAvailable;

			if (TotalRecords == 0)
				return 0;

			// First calculate the division
			//
			totalPagesAvailable = TotalRecords / PageSize;

			// Now do a mod for any remainder
			//
			if ((TotalRecords % PageSize) > 0)
				totalPagesAvailable++;

			return totalPagesAvailable;

		}

		
		int _pageIndex = 0;
		public virtual int PageIndex 
		{
			get 
			{
                // Give first try to the ViewState if it was a postback
                if (Page != null && Page.IsPostBack && ViewState["PageIndex"] != null){
                    _pageIndex = (int) ViewState["PageIndex"];
                }
                else {
                    if (csContext.QueryString["pageindex"] != null)
                        _pageIndex = int.Parse(csContext.QueryString["pageindex"]) - 1;
                }

				if (_pageIndex < 0)
					return 0;
				else
					return _pageIndex;
			}
			set 
			{
				ViewState["PageIndex"] = value;
				_pageIndex = value;
			}
		}

		public virtual int PageSize 
		{
			get 
			{
				int pageSize = Convert.ToInt32(ViewState["PageSize"]);

				if (pageSize == 0) 
					return 10;

				return pageSize;
			}
			set 
			{
				ViewState["PageSize"] = value;
			}

		}

		private bool _causeValidation = true;
		public bool CausesValidation
		{
			get {return _causeValidation;}
			set {_causeValidation = value;}
		}

		public int TotalRecords 
		{
			get 
			{
				return Convert.ToInt32(ViewState["TotalRecords"]);
			}
			set 
			{
				ViewState["TotalRecords"] = value;
			}
		}
		/// <summary>
		/// Making sure to strip the existing pager value from the querystring before appending a new one
		/// </summary>
		/// <param name="RawURL">Usually CSContext.Current.RawUrl</param>
		/// <param name="QueryName">Usually "pageindex"</param>
		/// <returns></returns>
		public string UrlCleaner(string RawURL, string QueryName)
		{
			// Configure the Url
			if(RawURL.IndexOf("?") != -1)
			{
				bool hasPart = false;
				string queryString = RawURL.Substring( RawURL.IndexOf("?") + 1 );
				string[] parts = queryString.Split('&');
				for(int i = 0 ; i < parts.Length ; i++)
				{
					if(parts[i].StartsWith(QueryName))
					{
						parts[i] = QueryName + "={0}";
						hasPart = true;
					}
				}
				if(hasPart == true)
					RawURL = RawURL.Replace(queryString, string.Join("&", parts));
				else
					RawURL = RawURL.Replace(queryString, string.Join("&", parts) + "&" + QueryName + "={0}");
			}
			else
				RawURL = RawURL + "?" + QueryName + "={0}";

			return RawURL;

		}

		#endregion

	}

	/// <summary>
	/// Summary description for Pager.
	/// </summary>
	public class AjaxPager : Label, IPagedControl
	{

		#region Member variables and constructor
		protected CSContext csContext = CSContext.Current;
		HyperLink previousLink;
		HyperLink nextLink;
		HyperLink firstLink;
		HyperLink lastLink;
		HyperLink[] pagingHyperLinks;

		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender (e);

			// Add Page buttons
			//
			AddPageLinks();

			// Add Previous Next child controls
			//
			AddPreviousNextLinks();

			// Add First Last child controls
			//
			AddFirstLastLinks();

		}
		#endregion

		#region Render functions
		protected override void Render(HtmlTextWriter writer) 
		{
			Render(writer, true);
		}

		protected virtual void Render(HtmlTextWriter writer, bool renderContainer)		
		{
			if (renderContainer)
				writer.Write("<div id=\"" + this.ClientID + "_Content\">");

			this.RenderChildren(writer);

			if (Visible)
			{
				int totalPages = CalculateTotalPages();

				// Do we have data?
				//
				if (totalPages > 1)
				{

					AddAttributesToRender(writer);


					// Render the paging buttons
					//
					writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);
					//writer.RenderBeginTag(HtmlTextWriterTag.Span);

					// Render the first button
					//
					if (this.ShowFirstLastLinks)
						RenderFirst(writer);

					// Render the previous button
					//
					RenderPrevious(writer);
            
					// Render the page button(s)
					//
					RenderPagingButtons(writer);

					// Render the next button
					//
					RenderNext(writer);

					// Render the last button
					//
					if (this.ShowFirstLastLinks)
						RenderLast(writer);

					//writer.RenderEndTag();
				}
			}

			if (renderContainer)
				writer.Write("</div>");
		}

		void RenderFirst (HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			if ((PageIndex >= 3) && (totalPages > 5)) 
			{
				firstLink.RenderControl(writer);

				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);
			}
		}

		void RenderLast (HtmlTextWriter writer) 
		{
			int totalPages = CalculateTotalPages();

			if (((PageIndex + 3) < totalPages) && (totalPages > 5)) 
			{
				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);

				lastLink.RenderControl(writer);
			}

		}

		void RenderPrevious (HtmlTextWriter writer) 
		{
			Literal l;

			if (HasPrevious) 
			{
				previousLink.RenderControl(writer);

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);
			}

		}

		void RenderNext(HtmlTextWriter writer) 
		{
			Literal l;

			if (HasNext) 
			{

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);

				nextLink.RenderControl(writer);
			}

		}

		void RenderButtonRange(int start, int end, HtmlTextWriter writer) 
		{

			for (int i = start; i < end; i++) 
			{

				// Are we working with the selected index?
				//
				if (PageIndex == i) 
				{

					// Render different output
					//
					Literal l = new Literal();
					//l.Text = "<span class=\"currentPage\">[" + (i + 1).ToString() + "]</span>";
					l.Text = (i + 1).ToString();

					l.RenderControl(writer);
				} 
				else 
				{
					pagingHyperLinks[i].RenderControl(writer);
				}
				if ( i < (end - 1) )
					writer.Write(" ");

			}

		}

		void RenderPagingButtons(HtmlTextWriter writer) 
		{
			int totalPages;

			// Get the total pages available
			//
			totalPages = CalculateTotalPages();

			// If we have <= 5 pages display all the pages and exit
			//
			if ( totalPages <= 5) 
			{
				RenderButtonRange(0, totalPages, writer);
			} 
			else 
			{

				int lowerBound = (PageIndex - 2);
				int upperBound = (PageIndex + 3);

				if (lowerBound <= 0) 
					lowerBound = 0;

				if (PageIndex == 0)
					RenderButtonRange(0, 5, writer);

				else if (PageIndex == 1)
					RenderButtonRange(0, (PageIndex + 4), writer);

				else if (PageIndex < (totalPages - 2))
					RenderButtonRange(lowerBound, (PageIndex + 3), writer);

				else if (PageIndex == (totalPages - 2))
					RenderButtonRange((totalPages - 5), (PageIndex + 2), writer);

				else if (PageIndex == (totalPages - 1))
					RenderButtonRange((totalPages - 5), (PageIndex + 1), writer);
			}
		}
		#endregion

		#region ControlTree functions
		void AddPageLinks() 
		{
			// First add the lower page buttons
			//
			pagingHyperLinks = new HyperLink[CalculateTotalPages()];

			// Create the buttons and add them to 
			// the Controls collection
			//
			for (int i = 0; i < pagingHyperLinks.Length; i++) 
			{
				pagingHyperLinks[i] = new HyperLink();
				pagingHyperLinks[i].EnableViewState = false;
				pagingHyperLinks[i].Text = (i + 1).ToString();
				pagingHyperLinks[i].ID = (i + 1).ToString();
				pagingHyperLinks[i].NavigateUrl = "#";
				pagingHyperLinks[i].Attributes.Add("onclick", CreatePagerJavaScript((i + 1).ToString()));
			}
		}

		void AddFirstLastLinks() 
		{
			int start = 1;
			firstLink = new HyperLink();
			firstLink.ID = "First";
			firstLink.Text = ResourceManager.GetString("Utility_Pager_firstButton");
			firstLink.NavigateUrl = "#";
			firstLink.Attributes.Add("onclick", CreatePagerJavaScript(start.ToString()));

			int last = CalculateTotalPages();
			lastLink = new HyperLink();
			lastLink.ID = "Last";
			lastLink.Text = ResourceManager.GetString("Utility_Pager_lastButton");
			lastLink.NavigateUrl = "#";
			lastLink.Attributes.Add("onclick", CreatePagerJavaScript(last.ToString()));
		}

		void AddPreviousNextLinks() 
		{
			int previous;
			
			if (this.PageIndex < 2)
				previous = 1;
			else
				previous = this.PageIndex;

			previousLink = new HyperLink();
			previousLink.ID = "Prev";
			previousLink.Text = ResourceManager.GetString("Utility_Pager_previousButton");
			previousLink.NavigateUrl = "#";
			previousLink.Attributes.Add("onclick", CreatePagerJavaScript(previous.ToString()));

			int next = this.PageIndex + 2;
			nextLink = new HyperLink();
			nextLink.ID = "Next";
			nextLink.Text = ResourceManager.GetString("Utility_Pager_nextButton");
			nextLink.NavigateUrl = "#";
			nextLink.Attributes.Add("onclick", CreatePagerJavaScript(next.ToString()));
		}
		#endregion

		#region Private Properties
		private bool HasPrevious 
		{
			get 
			{
				if (PageIndex > 0)
					return true;

				return false;
			}
		}

		private bool HasNext 
		{
			get 
			{
				if (PageIndex + 1 < CalculateTotalPages() )
					return true;

				return false;
			}
		}
		#endregion

		#region Helper methods and Public Properties

		string url = "AjaxPager.GetPage('{0}', {1}, new Function('result', 'if (result.error) {{ alert(result.error); }} else {{ document.getElementById(\\'{0}_Content\\').innerHTML = result.value; }}')); return false;";
		protected virtual string CreatePagerJavaScript(string pageIndex)
		{
			return string.Format(url, this.ClientID, pageIndex);
		}

		// *********************************************************************
		//  CalculateTotalPages
		//
		/// <summary>
		/// Static that caculates the total pages available.
		/// </summary>
		/// 
		// ********************************************************************/
		public virtual int CalculateTotalPages() 
		{
			int totalPagesAvailable;

			if (TotalRecords == 0)
				return 0;

			// First calculate the division
			//
			totalPagesAvailable = TotalRecords / PageSize;

			// Now do a mod for any remainder
			//
			if ((TotalRecords % PageSize) > 0)
				totalPagesAvailable++;

			return totalPagesAvailable;
		}
		
		int _pageIndex = -1;
		public virtual int PageIndex 
		{
			get 
			{
				// Give first try to the ViewState if it was a postback
				if (_pageIndex >= 0)
					return _pageIndex;
				else if (Page.IsPostBack && ViewState["PageIndex"] != null)
				{
					_pageIndex = (int) ViewState["PageIndex"];
				}
				else 
				{
					if (csContext.QueryString["pageindex"] != null)
						_pageIndex = int.Parse(csContext.QueryString["pageindex"]) - 1;
				}

				if (_pageIndex < 0)
					return 0;
				else
					return _pageIndex;
			}
			set 
			{
				ViewState["PageIndex"] = value;
				_pageIndex = value;
			}
		}

		public virtual int PageSize 
		{
			get 
			{
				int pageSize = Convert.ToInt32(ViewState["PageSize"]);

				if (pageSize == 0) 
					return 10;

				return pageSize;
			}
			set 
			{
				ViewState["PageSize"] = value;
			}

		}

		public virtual bool ShowFirstLastLinks
		{
			get
			{
				object state = ViewState["ShowFirstLastLinks"];
				if (state == null)
					return true;
				else
					return (bool) state;
			}
			set
			{
				ViewState["ShowFirstLastLinks"] = value;
			}
		}

		private bool _causeValidation = true;
		public bool CausesValidation
		{
			get {return _causeValidation;}
			set {_causeValidation = value;}
		}

		public int TotalRecords 
		{
			get 
			{
				return Convert.ToInt32(ViewState["TotalRecords"]);
			}
			set 
			{
				ViewState["TotalRecords"] = value;
			}
		}
		/// <summary>
		/// Making sure to strip the existing pager value from the querystring before appending a new one
		/// </summary>
		/// <param name="RawURL">Usually CSContext.Current.RawUrl</param>
		/// <param name="QueryName">Usually "pageindex"</param>
		/// <returns></returns>
		public string UrlCleaner(string RawURL, string QueryName)
		{
			// Configure the Url
			if(RawURL.IndexOf("?") != -1)
			{
				bool hasPart = false;
				string queryString = RawURL.Substring( RawURL.IndexOf("?") + 1 );
				string[] parts = queryString.Split('&');
				for(int i = 0 ; i < parts.Length ; i++)
				{
					if(parts[i].StartsWith(QueryName))
					{
						parts[i] = QueryName + "={0}";
						hasPart = true;
					}
				}
				if(hasPart == true)
					RawURL = RawURL.Replace(queryString, string.Join("&", parts));
				else
					RawURL = RawURL.Replace(queryString, string.Join("&", parts) + "&" + QueryName + "={0}");
			}
			else
				RawURL = RawURL + "?" + QueryName + "={0}";

			return RawURL;

		}

		#endregion

		public override bool Visible
		{
			get
			{
				object state = this.ViewState["Visible"];
				if (state == null)
					return true;
				else
					return (bool) state;
			}
			set
			{
				this.ViewState["Visible"] = value;
			}
		}

		#region AJAX

		protected override void OnInit(EventArgs e)
		{
			base.OnInit (e);
			AjaxManager.Register(this, "AjaxPager");
		}
		
		[AjaxMethod(IncludeControlValuesWithCallBack=true)]
		public virtual string GetPage(int page)
		{
			StringWriter stringWriter = new StringWriter();
			HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);

			AddPageLinks();
			AddPreviousNextLinks();

			if (this.ShowFirstLastLinks)
				AddFirstLastLinks();

			this.Render(htmlWriter, false);

			return stringWriter.ToString();
		}

		#endregion
	}

	public class LinkButtonPager : Label, IPagedControl, INamingContainer 
	{

		#region Member variables and constructor
		CSContext csContext = CSContext.Current;
		LinkButton previousButton;
		LinkButton nextButton;
		LinkButton firstButton;
		LinkButton lastButton;
		LinkButton[] pagingLinkButtons;

		// ***************************************************
		// Controls
		//
		/// <summary>
		/// Override how this control handles its controls collection
		/// </summary>
		/// 
		public override ControlCollection Controls 
		{

			get 
			{
				EnsureChildControls();
				return base.Controls;
			}

		}

		// *********************************************************************
		//  CreateChildControls
		//
		/// <summary>
		/// This event handler adds the children controls and is resonsible
		/// for determining the template type used for the control.
		/// </summary>
		/// 
		// ********************************************************************/ 
		protected override void CreateChildControls() 
		{
			Controls.Clear();

			// Add Page buttons
			//
			AddPageButtons();

			// Add Previous Next child controls
			//
			AddPreviousNextLinkButtons();

			// Add First Last child controls
			//
			AddFirstLastLinkButtons();

		}
		#endregion

		#region Render functions
		protected override void Render(HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			// Do we have data?
			//
			if (totalPages <= 1)
				return;

			AddAttributesToRender(writer);


			// Render the paging buttons
			//
			writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);
			//writer.RenderBeginTag(HtmlTextWriterTag.Span);

			// Render the first button
			//
			RenderFirst(writer);

			// Render the previous button
			//
			RenderPrevious(writer);
            
			// Render the page button(s)
			//
			RenderPagingButtons(writer);

			// Render the next button
			//
			RenderNext(writer);

			// Render the last button
			//
			RenderLast(writer);

			//writer.RenderEndTag();

		}

		void RenderFirst (HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			if ((PageIndex >= 3) && (totalPages > 5)) 
			{
				firstButton.RenderControl(writer);

				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);
			}
		}

		void RenderLast (HtmlTextWriter writer) 
		{

			int totalPages = CalculateTotalPages();

			if (((PageIndex + 3) < totalPages) && (totalPages > 5)) 
			{
				LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
				l.RenderControl(writer);

				lastButton.RenderControl(writer);
			}

		}

		void RenderPrevious (HtmlTextWriter writer) 
		{
			Literal l;

			if (HasPrevious) 
			{
				previousButton.RenderControl(writer);

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);
			}

		}

		void RenderNext(HtmlTextWriter writer) 
		{
			Literal l;

			if (HasNext) 
			{

				l = new Literal();
				l.Text = "&nbsp;";
				l.RenderControl(writer);

				nextButton.RenderControl(writer);
			}

		}

		void RenderButtonRange(int start, int end, HtmlTextWriter writer) 
		{

			for (int i = start; i < end; i++) 
			{

				// Are we working with the selected index?
				//
				if (PageIndex == i) 
				{

					// Render different output
					//
					Literal l = new Literal();
					//l.Text = "<span class=\"currentPage\">[" + (i + 1).ToString() + "]</span>";
					l.Text = (i + 1).ToString();

					l.RenderControl(writer);
				} 
				else 
				{
					pagingLinkButtons[i].RenderControl(writer);
				}
				if ( i < (end - 1) )
					writer.Write(" ");

			}

		}

		void RenderPagingButtons(HtmlTextWriter writer) 
		{
			int totalPages;

			// Get the total pages available
			//
			totalPages = CalculateTotalPages();

			// If we have <= 5 pages display all the pages and exit
			//
			if ( totalPages <= 5) 
			{
				RenderButtonRange(0, totalPages, writer);
			} 
			else 
			{

				int lowerBound = (PageIndex - 2);
				int upperBound = (PageIndex + 3);

				if (lowerBound <= 0) 
					lowerBound = 0;

				if (PageIndex == 0)
					RenderButtonRange(0, 5, writer);

				else if (PageIndex == 1)
					RenderButtonRange(0, (PageIndex + 4), writer);

				else if (PageIndex < (totalPages - 2))
					RenderButtonRange(lowerBound, (PageIndex + 3), writer);

				else if (PageIndex == (totalPages - 2))
					RenderButtonRange((totalPages - 5), (PageIndex + 2), writer);

				else if (PageIndex == (totalPages - 1))
					RenderButtonRange((totalPages - 5), (PageIndex + 1), writer);
			}
		}
		#endregion

		#region ControlTree functions
		void AddPageButtons() 
		{

			// First add the lower page buttons
			//
			pagingLinkButtons = new LinkButton[CalculateTotalPages()];

			// Create the buttons and add them to 
			// the Controls collection
			//
			for (int i = 0; i < pagingLinkButtons.Length; i++) 
			{

				pagingLinkButtons[i] = new LinkButton();
				pagingLinkButtons[i].EnableViewState = false;
				pagingLinkButtons[i].Text = (i + 1).ToString();
				pagingLinkButtons[i].ID = i.ToString();
				pagingLinkButtons[i].CommandArgument = i.ToString();
				pagingLinkButtons[i].Click += new System.EventHandler(PageIndex_Click);
				pagingLinkButtons[i].CausesValidation = this.CausesValidation;
				Controls.Add(pagingLinkButtons[i]);

			}


		}

		void AddFirstLastLinkButtons() 
		{

			// Create the previous button if necessary
			//
			firstButton = new LinkButton();
			firstButton.ID = "First";
			firstButton.Text = ResourceManager.GetString("Utility_Pager_firstButton");
			firstButton.CommandArgument = "0";
			firstButton.Click += new System.EventHandler(PageIndex_Click);
			firstButton.CausesValidation = this.CausesValidation;
			Controls.Add(firstButton);

			// Create the next button if necessary
			//
			lastButton = new LinkButton();
			lastButton.ID = "Last";
			lastButton.Text = ResourceManager.GetString("Utility_Pager_lastButton");
			lastButton.CommandArgument = (CalculateTotalPages() - 1).ToString();
			lastButton.Click += new System.EventHandler(PageIndex_Click);
			lastButton.CausesValidation = this.CausesValidation;
			Controls.Add(lastButton);

		}

		void AddPreviousNextLinkButtons() 
		{

			// Create the previous button if necessary
			//
			previousButton = new LinkButton();
			previousButton.ID = "Prev";
			previousButton.Text = ResourceManager.GetString("Utility_Pager_previousButton");
			previousButton.CommandArgument = (PageIndex - 1).ToString();
			previousButton.Click += new System.EventHandler(PageIndex_Click);
			previousButton.CausesValidation = this.CausesValidation;
			Controls.Add(previousButton);

			// Create the next button if necessary
			//
			nextButton = new LinkButton();
			nextButton.ID = "Next";
			nextButton.Text = ResourceManager.GetString("Utility_Pager_nextButton");
			nextButton.CommandArgument = (PageIndex + 1).ToString();
			nextButton.Click += new System.EventHandler(PageIndex_Click);
			nextButton.CausesValidation = this.CausesValidation;
			Controls.Add(nextButton);

		}
		#endregion

		#region Private Properties
		private bool HasPrevious 
		{
			get 
			{
				if (PageIndex > 0)
					return true;

				return false;
			}
		}

		private bool HasNext 
		{
			get 
			{
				if (PageIndex + 1 < CalculateTotalPages() )
					return true;

				return false;
			}
		}
		#endregion

		#region Events
		// *********************************************************************
		//  IndexChanged
		//
		/// <summary>
		/// Event raised when a an index has been selected by the end user
		/// </summary>
		/// 
		// ********************************************************************/
		public event System.EventHandler IndexChanged;

		public event PagerEventHandler PagerIndexChange;

		// *********************************************************************
		//  PageIndex_Click
		//
		/// <summary>
		/// Event raised when a new index is selected from the paging control
		/// </summary>
		/// 
		// ********************************************************************/
		void PageIndex_Click(Object sender, EventArgs e) 
		{

			PageIndex = Convert.ToInt32(((LinkButton) sender).CommandArgument);

			if (null != IndexChanged)
				IndexChanged(sender, e);

			if(null != PagerIndexChange)
				PagerIndexChange(sender, new PagerEventArgs(this.PageSize,this.PageIndex,this.TotalRecords));

		}
		#endregion

		#region Helper methods and Public Properties
		// *********************************************************************
		//  CalculateTotalPages
		//
		/// <summary>
		/// Static that caculates the total pages available.
		/// </summary>
		/// 
		// ********************************************************************/
		public int CalculateTotalPages() 
		{
			int totalPagesAvailable;

			if (TotalRecords == 0)
				return 0;

			// First calculate the division
			//
			totalPagesAvailable = TotalRecords / PageSize;

			// Now do a mod for any remainder
			//
			if ((TotalRecords % PageSize) > 0)
				totalPagesAvailable++;

			return totalPagesAvailable;

		}

		public int PageIndex 
		{
			get 
			{
				int _pageIndex = 0;

				if ((!Page.IsPostBack) && (csContext.PageIndex > 0))
					_pageIndex = csContext.PageIndex;
				else
					_pageIndex = Convert.ToInt32(ViewState["PageIndex"]);

				if (_pageIndex < 0)
					return 0;
				else
					return _pageIndex;
			}
			set 
			{
				ViewState["PageIndex"] = value;
			}
		}

		public virtual int PageSize 
		{
			get 
			{
				int pageSize = Convert.ToInt32(ViewState["PageSize"]);

				if (pageSize == 0) 
					return 10;

				return pageSize;
			}
			set 
			{
				ViewState["PageSize"] = value;
			}

		}

		private bool _causeValidation = true;
		public bool CausesValidation
		{
			get {return _causeValidation;}
			set {_causeValidation = value;}
		}

		public int TotalRecords 
		{
			get 
			{
				return Convert.ToInt32(ViewState["TotalRecords"]);
			}
			set 
			{
				ViewState["TotalRecords"] = value;
			}
		}
		#endregion

	}

	public delegate void PagerEventHandler(object sender, PagerEventArgs e);

	public class PagerEventArgs : EventArgs
	{
		public PagerEventArgs(int pageSize, int pageIndex, int totalRecords)
		{
			_pageSize = pageSize;
			_pageIndex = pageIndex;
			_totalRecords = totalRecords;
		}

		int _pageSize, _pageIndex, _totalRecords;

		public int PageSize { get{ return _pageSize;}}
		public int PageIndex { get{ return _pageIndex;}}
		public int TotalRecords { get{ return _totalRecords;}}
	}
}
